/* Scene.cpp  -- scene representation 

Copyright (C) 2010 Gabriel Alises Cano, Javier Angulo Lucerón

This file is part of Computer Graphics : Final Project 09-10.

Computer Graphics : Final Project 09-10 is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
Computer Graphics : Final Project 09-10 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with Computer Graphics : Final Project 09-10.  If not, see <http://www.gnu.org/licenses/>. */

#include "Scene.h"

Scene::Scene (Camera *cam)
{
	this->cam = cam;
}

Scene::~Scene ()
{
}

GLuint
Scene::add_object (Object3D *o)
{
	objects.push_back (o);
	return objects.size ();
}

vector<Object3D *> 
Scene::get_objects ()
{
	return objects;
}

Camera *
Scene::get_cam()
{
	return cam;
}


void 
Scene::set_state (TState st)
{
	state = st;
}

TState 
Scene::get_state ()
{
	return state;
}

void
Scene::delete_object (GLuint n)
{
	objects.erase (objects.begin () + n);
}

GLuint
Scene::select_all ()
{
	for (vector<Object3D *>::iterator it = objects.begin (); it != objects.end (); it ++)
		(*it)->set_state (SELECTED);
	return objects.size ();
}

void
Scene::deselect_all ()
{
	for (vector<Object3D *>::iterator it = objects.begin (); it != objects.end (); it ++)
 		(*it)->set_state (NORMAL);
}

GLuint
Scene::select_inverse ()
{
	int count = 0;
	for (vector<Object3D *>::iterator it = objects.begin (); it != objects.end (); it ++)
		if ((*it)->get_state () != NORMAL)
			(*it)->set_state (NORMAL);
		else
			{
				(*it)->set_state (SELECTED);    
				count++;
			}
	return count;
}

GLuint
Scene::select_object (GLuint n)
{
	if (n + 1 > objects.size ())
		return 1;       
	objects.at (n)->set_state (SELECTED);
	return 0;
}

void
Scene::deselect_object (GLuint n)
{
	if (n + 1 > objects.size ())
		return;
	objects.at (n)->set_state (NORMAL);
}

TState 
Scene::get_state_i (GLuint n)
{
	return objects[n]->get_state (); 
}
		
Triangle * 
Scene::edit_face (GLuint n_obj, GLuint n_triang)
{
	Object3D *o = objects[n_obj];
	Triangle *t = o->get_triangs ()[n_triang];
	vector<Triangle *> face = o->get_face (t);
	for (vector<Triangle *>::iterator it = face.begin (); it != face.end (); it++)
		(*it)->set_state (EDITED);
	return t;
}	

GLuint 
Scene::get_n_selected_objects ()
{
	GLuint n = 0;
	for (vector<Object3D *>::iterator it = objects.begin (); it != objects.end (); it++)
		if ((*it)->get_state () == SELECTED)
			n++;
	return n;
}

vector<GLuint> 
Scene::get_selected_objects ()
{
	vector<GLuint> selected;
	for (vector<Object3D *>::iterator it = objects.begin (); it != objects.end (); it++)
		if ((*it)->get_state () == SELECTED)
			selected.push_back (it - objects.begin ());
	return selected;
}


GLuint 
Scene::edit_object (GLuint n)
{
	if (n + 1 > objects.size ())
		return 1;
	this->dont_edit ();
	objects.at(n)->set_state (EDITED);
	return 0;
}

void 
Scene::dont_edit ()
{
	for (vector<Object3D *>::iterator it = objects.begin (); it != objects.end (); it++)
		{
			(*it)->set_state (NORMAL);
			vector<Triangle *> t = (*it)->get_triangs ();
			for (vector<Triangle *>::iterator jt = t.begin (); jt != t.end (); jt++)
				(*jt)->set_state (NORMAL);
		}
}

void
Scene::dont_edit_face ()
{
	bool end = false;
	for (vector<Object3D *>::iterator it = objects.begin (); it != objects.end () && end == false; it++)
		{
			vector<Triangle *> t = (*it)->get_triangs ();
			for (vector<Triangle *>::iterator jt = t.begin (); jt != t.end () && end == false; jt++)
				if ((*jt)->get_state () == EDITED)
					{	
						(*jt)->set_state (NORMAL);
						end = true;
					}
		}
}

void 
Scene::move (Vertex3D pos)
{
	for (vector<Object3D *>::iterator it = objects.begin (); it != objects.end (); it ++)
		if ((*it)->get_state () == SELECTED)
			(*it)->move (pos);
}

void 
Scene::scale (GLdouble factor, TAxis axis)
{
	for (vector<Object3D *>::iterator it = objects.begin (); it != objects.end (); it ++)
		if ((*it)->get_state () == SELECTED)
			(*it)->scale (factor, axis);
}

void 
Scene::rotate (GLdouble degree, TAxis axis)
{
	for (vector<Object3D *>::iterator it = objects.begin (); it != objects.end (); it ++)
		if ((*it)->get_state () == SELECTED)
			(*it)->rotate (degree, axis);
}

void 
Scene::extrude (Triangle *t, GLdouble dist)
{
	for (vector<Object3D *>::iterator it = objects.begin (); it != objects.end (); it ++)
		if ((*it)->get_state () == EDITED)
			{
				(*it)->extrude (t, dist);
				break;
			}
}

void
Scene::merge(GLuint a, GLuint b)
{
	objects.at(a)->merge(objects.at(b));
	objects.erase(objects.begin() + b);
}

void
Scene::draw ()
{
	int n = 0;
	for (vector<Object3D *>::iterator it = objects.begin (); it != objects.end (); it ++)
		{
			if (state == NORMAL)
				glLoadName (n++);
			(*it)->draw ();
		}
}

void 
Scene::insert_plane (GLdouble x, GLdouble y)
{


}

void 
Scene::insert_cube (GLdouble side)
{


}

void 
Scene::insert_sphere (GLdouble radius)
{


}

void 
Scene::insert_pyramid (GLuint base_side_n, GLdouble base_side, GLdouble height)
{


}

void 
Scene::insert_monkey ()
{


}

void 
Scene::insert_teapot ()
{


}


